#ifndef RAPIDXML_UTILS_HPP_INCLUDED
#define RAPIDXML_UTILS_HPP_INCLUDED

// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.

#include "rapidxml.hpp"
#include <vector>
#include <string>
#include <fstream>
#include <stdexcept>

namespace behaviac
{
	namespace rapidxml
	{
		//! Represents data loaded from a file
		template<class Ch = char>
		class file
		{
		public:

			//! Loads file into the memory. Data will be automatically destroyed by the destructor.
			//! \param filename Filename to load.
			file(const char* filename)
			{
				using namespace std;

				// Open stream
				basic_ifstream<Ch> stream(filename, ios::binary);

				if (!stream)
				{
					throw runtime_error(string("cannot open file ") + filename);
				}

				stream.unsetf(ios::skipws);

				// Determine stream size
				stream.seekg(0, ios::end);
				size_t size = stream.tellg();
				stream.seekg(0);

				// Load data and add terminating 0
				m_data.resize(size + 1);
				stream.read(&m_data.front(), static_cast<streamsize>(size));
				m_data[size] = 0;
			}

			//! Loads file into the memory. Data will be automatically destroyed by the destructor
			//! \param stream Stream to load from
			file(std::basic_istream<Ch>& stream)
			{
				using namespace std;

				// Load data and add terminating 0
				stream.unsetf(ios::skipws);
				m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());

				if (stream.fail() || stream.bad())
				{
					throw runtime_error("error reading stream");
				}

				m_data.push_back(0);
			}

			//! Gets file data.
			//! \return Pointer to data of file.
			Ch* data()
			{
				return &m_data.front();
			}

			//! Gets file data.
			//! \return Pointer to data of file.
			const Ch* data() const
			{
				return &m_data.front();
			}

			//! Gets file data size.
			//! \return Size of file data, in characters.
			std::size_t size() const
			{
				return m_data.size();
			}

		private:

			std::vector<Ch> m_data;   // File data
		};

		//! Counts children of node. Time complexity is O(n).
		//! \return Number of children of node
		template<class Ch>
		inline std::size_t count_children(xml_node<Ch>* node)
		{
			xml_node<Ch>* child = node->first_node();
			std::size_t count = 0;

			while (child)
			{
				++count;
				child = child->next_sibling();
			}

			return count;
		}

		//! Counts attributes of node. Time complexity is O(n).
		//! \return Number of attributes of node
		template<class Ch>
		inline std::size_t count_attributes(xml_node<Ch>* node)
		{
			xml_attribute<Ch>* attr = node->first_attribute();
			std::size_t count = 0;

			while (attr)
			{
				++count;
				attr = attr->next_attribute();
			}

			return count;
		}
	}
}

#endif
